package com.atguigu.tingshu.live.api;

import com.alibaba.fastjson.JSON;
import com.atguigu.tingshu.live.util.WebSocketLocalContainerUtil;
import com.atguigu.tingshu.model.live.FromUser;
import com.atguigu.tingshu.model.live.SocketMsg;
import com.atguigu.tingshu.model.user.UserInfo;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

/**
 * @author atguigu-mqx
 * @ClassName WebSocketApiController
 * @description: TODO
 * @date 2024年01月10日
 * @version: 1.0
 */
@ServerEndpoint(value = "/api/websocket/{liveRoomId}/{token}")
@Component
@Slf4j
public class WebSocketApiController {

    private static RedisTemplate redisTemplate;

    //  注入
    @Autowired
    public void setRedisTemplate(RedisTemplate redisTemplate) {
        WebSocketApiController.redisTemplate = redisTemplate;
    }


    /**
     * 创建连接
     *
     * @param session
     * @param liveRoomId
     * @param token
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("liveRoomId") Long liveRoomId, @PathParam("token") String token) {
        //  谁谁谁进入直播间.
        log.info("建立连接，liveRoomId：{}， token：{}", liveRoomId, token);
        //  获取用户Id
        //  从redis 中获取用户信息.
        String userKey = "user:login:" + token;
        UserInfo userInfo = (UserInfo) this.redisTemplate.opsForValue().get(userKey);
        //  判断用户对象为空则返回
        if (null == userInfo) return;
        //  获取用户Id
        Long userId = userInfo.getId();
        //  创建对象
        FromUser fromUser = new FromUser();
        fromUser.setUserId(userId);
        fromUser.setNickname(userInfo.getNickname());
        fromUser.setAvatarUrl(userInfo.getAvatarUrl());
        //  绑定容器：
        WebSocketLocalContainerUtil.addSession(userId, session);
        WebSocketLocalContainerUtil.addFromUser(userId, fromUser);
        WebSocketLocalContainerUtil.addUserIdToLiveRoom(liveRoomId, userId);
        //  提示：xxx加入直播间.
        SocketMsg socketMsg = WebSocketLocalContainerUtil.buildSocketMsg(liveRoomId, fromUser, SocketMsg.MsgTypeEnum.JOIN_CHAT, userInfo.getNickname() + "进入直播间");
        //  发送消息.
        WebSocketLocalContainerUtil.sendMsg(socketMsg);

    }

    /**
     * 断开连接
     *
     * @param session
     * @param liveRoomId
     * @param token
     */
    @OnClose
    public void onClose(Session session, @PathParam("liveRoomId") Long liveRoomId, @PathParam("token") String token) {
        //  谁谁谁进入直播间.
        log.info("断开连接，liveRoomId：{}， token：{}", liveRoomId, token);
        //  从redis 中获取用户信息.
        String userKey = "user:login:" + token;
        UserInfo userInfo = (UserInfo) this.redisTemplate.opsForValue().get(userKey);
        //  判断用户对象为空则返回
        if (null == userInfo) return;
        //  获取用户Id
        Long userId = userInfo.getId();
        //  创建对象
        FromUser fromUser = new FromUser();
        fromUser.setUserId(userId);
        fromUser.setNickname(userInfo.getNickname());
        fromUser.setAvatarUrl(userInfo.getAvatarUrl());
        //  提示：xxx加入直播间.
        SocketMsg socketMsg = WebSocketLocalContainerUtil.buildSocketMsg(liveRoomId, fromUser, SocketMsg.MsgTypeEnum.CLOSE_SOCKET, userInfo.getNickname() + "退出直播间");
        //  删除数据
        WebSocketLocalContainerUtil.removeSession(userId);
        WebSocketLocalContainerUtil.removeFromUser(userId);
        WebSocketLocalContainerUtil.removeUserIdToLiveRoom(liveRoomId, userId);
        //  提示：xxx退出直播间.
        //  发送消息.
        WebSocketLocalContainerUtil.sendMsg(socketMsg);

    }

    /**
     * 发送消息
     *
     * @param message
     */
    @OnMessage
    public void onMessage(String message) {
        //  谁谁谁进入直播间.
        log.info("发送消息，{}", message);
        //  数据类型转换：必须以SocketMsg实体类的json形式发送消息
        //  发送消息.
        //  WebSocketLocalContainerUtil.sendMsg(JSON.parseObject(message, SocketMsg.class));
        //  redis 订阅与发布
        redisTemplate.convertAndSend("message:list",message);

    }

    /**
     * 发生错误
     *
     * @param session
     */
    @OnError
    public void onError(Session session, Throwable throwable) {
        log.error("发生错误..."+throwable.getMessage());
    }
}
